# -*- coding: utf-8 -*-
# @version        : 1.0
# @Create Time    : 2021/10/19 15:47
# @File           : main.py
# @IDE            : PyCharm
# @desc           : 主程序入口


from fastapi import FastAPI
import uvicorn
from starlette.staticfiles import StaticFiles
from application import settings
from application import urls
from starlette.middleware.cors import CORSMiddleware
from core import register_exception
from utils.tools import import_module
from core.event import lifespan
import typer
import subprocess


shell_app = typer.Typer()


def create_app():
    """
    启动项目

    docs_url：配置交互文档的路由地址，如果禁用则为None，默认为 /docs
    redoc_url： 配置 Redoc 文档的路由地址，如果禁用则为None，默认为 /redoc
    openapi_url：配置接口文件json数据文件路由地址，如果禁用则为None，默认为/openapi.json
    """
    app = FastAPI(
        title="FastAPI 示例项目",
        description="融入了Mysql，WebSocket，Redis的简单使用方式",
        version=settings.VERSION,
        docs_url="/docs",
        lifespan=lifespan
    )
    import_module(settings.MIDDLEWARES, "中间件", app=app)
    # 全局异常捕捉处理
    register_exception(app)
    # 跨域解决
    if settings.CORS_ORIGIN_ENABLE:
        app.add_middleware(
            CORSMiddleware,
            allow_origins=settings.ALLOW_ORIGINS,
            allow_credentials=settings.ALLOW_CREDENTIALS,
            allow_methods=settings.ALLOW_METHODS,
            allow_headers=settings.ALLOW_HEADERS
        )
    # 挂在静态目录
    if settings.STATIC_ENABLE:
        app.mount(settings.STATIC_URL, app=StaticFiles(directory=settings.STATIC_ROOT))
    # 引入应用中的路由
    for url in urls.urlpatterns:
        app.include_router(url["ApiRouter"], prefix=url["prefix"], tags=url["tags"])
    return app


@shell_app.command()
def run():
    """
    启动项目

    factory: 在使用 uvicorn.run() 启动 ASGI 应用程序时，可以通过设置 factory 参数来指定应用程序工厂。
    应用程序工厂是一个返回 ASGI 应用程序实例的可调用对象，它可以在启动时动态创建应用程序实例。
    """
    uvicorn.run(
        app='main:create_app',
        host="0.0.0.0",
        port=8000,
        lifespan="on",
        factory=True,
        proxy_headers=True,
        forwarded_allow_ips="*"
    )


@shell_app.command()
def init():
    """
    初始化数据
    """
    print("开始初始化数据")
    subprocess.check_call(['alembic', 'revision', '-m', 'first'], cwd=settings.BASE_DIR)
    subprocess.check_call(['alembic', 'upgrade', 'head'], cwd=settings.BASE_DIR)
    subprocess.check_call(['alembic', 'revision', '--autogenerate', '-m', f'{settings.VERSION}'], cwd=settings.BASE_DIR)
    subprocess.check_call(['alembic', 'upgrade', 'head'], cwd=settings.BASE_DIR)
    print(f"{settings.VERSION} 数据库表迁移完成")


if __name__ == '__main__':
    shell_app()
